home *** CD-ROM | disk | FTP | other *** search
/ X User Tools / X User Tools (O'Reilly and Associates)(1994).ISO / sources / libxpm / libxpm34.gz / libxpm34 / xpm-3.4 / lib / data.c < prev    next >
C/C++ Source or Header  |  1994-03-14  |  14KB  |  646 lines

  1. /* Copyright 1989-94 GROUPE BULL -- See license conditions in file COPYRIGHT */
  2. /*****************************************************************************\
  3. * data.c:                                                                     *
  4. *                                                                             *
  5. *  XPM library                                                                *
  6. *  IO utilities                                                               *
  7. *                                                                             *
  8. *  Developed by Arnaud Le Hors                                                *
  9. \*****************************************************************************/
  10.  
  11. /* Official version number */
  12. static char *RCS_Version = "$XpmVersion: 3.4 $";
  13.  
  14. /* Internal version number */
  15. static char *RCS_Id = "$Id: xpm.shar,v 3.24 1994/03/14 16:16:26 lehors Exp $";
  16.  
  17. #include "xpmP.h"
  18. #ifdef VMS
  19. #include "sys$library:stat.h"
  20. #include "sys$library:ctype.h"
  21. #else
  22. #include <sys/stat.h>
  23. #include <ctype.h>
  24. #endif
  25.  
  26. FUNC(atoui, unsigned int, (char *p, unsigned int l, unsigned int *ui_return));
  27. LFUNC(ParseComment, int, (xpmData * mdata));
  28.  
  29. unsigned int
  30. atoui(p, l, ui_return)
  31.     register char *p;
  32.     unsigned int l;
  33.     unsigned int *ui_return;
  34. {
  35.     register int n, i;
  36.  
  37.     n = 0;
  38.     for (i = 0; i < l; i++)
  39.     if (*p >= '0' && *p <= '9')
  40.         n = n * 10 + *p++ - '0';
  41.     else
  42.         break;
  43.  
  44.     if (i != 0 && i == l) {
  45.     *ui_return = n;
  46.     return 1;
  47.     } else
  48.     return 0;
  49. }
  50.  
  51. static int
  52. ParseComment(mdata)
  53.     xpmData *mdata;
  54. {
  55.     if (mdata->type == XPMBUFFER) {
  56.     register char c;
  57.     register unsigned int n = 0;
  58.     unsigned int notend;
  59.     char *s, *s2;
  60.  
  61.     s = mdata->Comment;
  62.     *s = mdata->Bcmt[0];
  63.  
  64.     /* skip the string beginning comment */
  65.     s2 = mdata->Bcmt;
  66.     do {
  67.         c = *mdata->cptr++;
  68.         *++s = c;
  69.         n++;
  70.         s2++;
  71.     } while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
  72.  
  73.     if (*s2 != '\0') {
  74.         /* this wasn't the beginning of a comment */
  75.         mdata->cptr -= n;
  76.         return 0;
  77.     }
  78.     /* store comment */
  79.     mdata->Comment[0] = *s;
  80.     s = mdata->Comment;
  81.     notend = 1;
  82.     n = 0;
  83.     while (notend) {
  84.         s2 = mdata->Ecmt;
  85.         while (*s != *s2 && c && c != mdata->Bos) {
  86.         c = *mdata->cptr++;
  87.         *++s = c;
  88.         n++;
  89.         }
  90.         mdata->CommentLength = n;
  91.         do {
  92.         c = *mdata->cptr++;
  93.         n++;
  94.         *++s = c;
  95.         s2++;
  96.         } while (c == *s2 && *s2 != '\0' && c && c != mdata->Bos);
  97.         if (*s2 == '\0') {
  98.         /* this is the end of the comment */
  99.         notend = 0;
  100.         mdata->cptr--;
  101.         }
  102.     }
  103.     return 0;
  104.     } else {
  105.     FILE *file = mdata->stream.file;
  106.     register int c;
  107.     register unsigned int n = 0, a;
  108.     unsigned int notend;
  109.     char *s, *s2;
  110.  
  111.     s = mdata->Comment;
  112.     *s = mdata->Bcmt[0];
  113.  
  114.     /* skip the string beginning comment */
  115.     s2 = mdata->Bcmt;
  116.     do {
  117.         c = getc(file);
  118.         *++s = c;
  119.         n++;
  120.         s2++;
  121.     } while (c == *s2 && *s2 != '\0'
  122.          && c != EOF && c != mdata->Bos);
  123.  
  124.     if (*s2 != '\0') {
  125.         /* this wasn't the beginning of a comment */
  126.         /* put characters back in the order that we got them */
  127.         for (a = n; a > 0; a--, s--)
  128.         ungetc(*s, file);
  129.         return 0;
  130.     }
  131.     /* store comment */
  132.     mdata->Comment[0] = *s;
  133.     s = mdata->Comment;
  134.     notend = 1;
  135.     n = 0;
  136.     while (notend) {
  137.         s2 = mdata->Ecmt;
  138.         while (*s != *s2 && c != EOF && c != mdata->Bos) {
  139.         c = getc(file);
  140.         *++s = c;
  141.         n++;
  142.         }
  143.         mdata->CommentLength = n;
  144.         do {
  145.         c = getc(file);
  146.         n++;
  147.         *++s = c;
  148.         s2++;
  149.         } while (c == *s2 && *s2 != '\0'
  150.              && c != EOF && c != mdata->Bos);
  151.         if (*s2 == '\0') {
  152.         /* this is the end of the comment */
  153.         notend = 0;
  154.         ungetc(*s, file);
  155.         }
  156.     }
  157.     return 0;
  158.     }
  159. }
  160.  
  161. /*
  162.  * skip to the end of the current string and the beginning of the next one
  163.  */
  164. int
  165. xpmNextString(mdata)
  166.     xpmData *mdata;
  167. {
  168.     if (!mdata->type)
  169.     mdata->cptr = (mdata->stream.data)[++mdata->line];
  170.     else if (mdata->type == XPMBUFFER) {
  171.     register char c;
  172.  
  173.     /* get to the end of the current string */
  174.     if (mdata->Eos)
  175.         while ((c = *mdata->cptr++) && c != mdata->Eos);
  176.  
  177.     /*
  178.      * then get to the beginning of the next string looking for possible
  179.      * comment
  180.      */
  181.     if (mdata->Bos) {
  182.         while ((c = *mdata->cptr++) && c != mdata->Bos)
  183.         if (mdata->Bcmt && c == mdata->Bcmt[0])
  184.             ParseComment(mdata);
  185.     } else if (mdata->Bcmt) {    /* XPM2 natural */
  186.         while ((c = *mdata->cptr++) == mdata->Bcmt[0])
  187.         ParseComment(mdata);
  188.         mdata->cptr--;
  189.     }
  190.     } else {
  191.     register int c;
  192.     FILE *file = mdata->stream.file;
  193.  
  194.     /* get to the end of the current string */
  195.     if (mdata->Eos)
  196.         while ((c = getc(file)) != mdata->Eos && c != EOF);
  197.  
  198.     /*
  199.      * then get to the beginning of the next string looking for possible
  200.      * comment
  201.      */
  202.     if (mdata->Bos) {
  203.         while ((c = getc(file)) != mdata->Bos && c != EOF)
  204.         if (mdata->Bcmt && c == mdata->Bcmt[0])
  205.             ParseComment(mdata);
  206.  
  207.     } else if (mdata->Bcmt) {    /* XPM2 natural */
  208.         while ((c = getc(file)) == mdata->Bcmt[0])
  209.         ParseComment(mdata);
  210.         ungetc(c, file);
  211.     }
  212.     }
  213.     return 0;
  214. }
  215.  
  216.  
  217. /*
  218.  * skip whitespace and compute the following unsigned int,
  219.  * returns 1 if one is found and 0 if not
  220.  */
  221. int
  222. xpmNextUI(mdata, ui_return)
  223.     xpmData *mdata;
  224.     unsigned int *ui_return;
  225. {
  226.     char buf[BUFSIZ];
  227.     int l;
  228.  
  229.     l = xpmNextWord(mdata, buf, BUFSIZ);
  230.     return atoui(buf, l, ui_return);
  231. }
  232.  
  233. /*
  234.  * skip whitespace and return the following word
  235.  */
  236. unsigned int
  237. xpmNextWord(mdata, buf, buflen)
  238.     xpmData *mdata;
  239.     char *buf;
  240.     unsigned int buflen;
  241. {
  242.     register unsigned int n = 0;
  243.     int c;
  244.  
  245.     if (!mdata->type || mdata->type == XPMBUFFER) {
  246.     while (isspace(c = *mdata->cptr) && c != mdata->Eos)
  247.         mdata->cptr++;
  248.     do {
  249.         c = *mdata->cptr++;
  250.         *buf++ = c;
  251.         n++;
  252.     } while (!isspace(c) && c != mdata->Eos && n < buflen);
  253.     n--;
  254.     mdata->cptr--;
  255.     } else {
  256.     FILE *file = mdata->stream.file;
  257.  
  258.     while ((c = getc(file)) != EOF && isspace(c) && c != mdata->Eos);
  259.     while (!isspace(c) && c != mdata->Eos && c != EOF && n < buflen) {
  260.         *buf++ = c;
  261.         n++;
  262.         c = getc(file);
  263.     }
  264.     ungetc(c, file);
  265.     }
  266.     return (n);
  267. }
  268.  
  269. /*
  270.  * return end of string - WARNING: malloc!
  271.  */
  272. int
  273. xpmGetString(mdata, sptr, l)
  274.     xpmData *mdata;
  275.     char **sptr;
  276.     unsigned int *l;
  277. {
  278.     unsigned int i, n = 0;
  279.     int c;
  280.     char *p, *q, buf[BUFSIZ];
  281.  
  282.     if (!mdata->type || mdata->type == XPMBUFFER) {
  283.     if (mdata->cptr) {
  284.         char *start;
  285.  
  286.         while (isspace(c = *mdata->cptr) && c != mdata->Eos)
  287.         mdata->cptr++;
  288.         start = mdata->cptr;
  289.         while ((c = *mdata->cptr) && c != mdata->Eos)
  290.         mdata->cptr++;
  291.         n = mdata->cptr - start + 1;
  292.         p = (char *) XpmMalloc(n);
  293.         if (!p)
  294.         return (XpmNoMemory);
  295.         strncpy(p, start, n);
  296.         if (mdata->type)        /* XPMBUFFER */
  297.         p[n - 1] = '\0';
  298.     }
  299.     } else {
  300.     FILE *file = mdata->stream.file;
  301.  
  302.     while ((c = getc(file)) != EOF && isspace(c) && c != mdata->Eos);
  303.     if (c == EOF)
  304.         return (XpmFileInvalid);
  305.     p = NULL;
  306.     i = 0;
  307.     q = buf;
  308.     p = (char *) XpmMalloc(1);
  309.     while (c != mdata->Eos && c != EOF) {
  310.         if (i == BUFSIZ) {
  311.         /* get to the end of the buffer */
  312.         /* malloc needed memory */
  313.         q = (char *) XpmRealloc(p, n + i);
  314.         if (!q) {
  315.             XpmFree(p);
  316.             return (XpmNoMemory);
  317.         }
  318.         p = q;
  319.         q += n;
  320.         /* and copy what we already have */
  321.         strncpy(q, buf, i);
  322.         n += i;
  323.         i = 0;
  324.         q = buf;
  325.         }
  326.         *q++ = c;
  327.         i++;
  328.         c = getc(file);
  329.     }
  330.     if (c == EOF) {
  331.         XpmFree(p);
  332.         return (XpmFileInvalid);
  333.     }
  334.     if (n + i != 0) {
  335.         /* malloc needed memory */
  336.         q = (char *) XpmRealloc(p, n + i + 1);
  337.         if (!q) {
  338.         XpmFree(p);
  339.         return (XpmNoMemory);
  340.         }
  341.         p = q;
  342.         q += n;
  343.         /* and copy the buffer */
  344.         strncpy(q, buf, i);
  345.         n += i;
  346.         p[n++] = '\0';
  347.     } else {
  348.         *p = '\0';
  349.         n = 1;
  350.     }
  351.     ungetc(c, file);
  352.     }
  353.     *sptr = p;
  354.     *l = n;
  355.     return (XpmSuccess);
  356. }
  357.  
  358. /*
  359.  * get the current comment line
  360.  */
  361. int
  362. xpmGetCmt(mdata, cmt)
  363.     xpmData *mdata;
  364.     char **cmt;
  365. {
  366.     if (!mdata->type)
  367.     *cmt = NULL;
  368.     else if (mdata->CommentLength) {
  369.     *cmt = (char *) XpmMalloc(mdata->CommentLength + 1);
  370.     strncpy(*cmt, mdata->Comment, mdata->CommentLength);
  371.     (*cmt)[mdata->CommentLength] = '\0';
  372.     mdata->CommentLength = 0;
  373.     } else
  374.     *cmt = NULL;
  375.     return 0;
  376. }
  377.  
  378. /*
  379.  * open the given file to be read as an xpmData which is returned.
  380.  */
  381. int
  382. xpmReadFile(filename, mdata)
  383.     char *filename;
  384.     xpmData *mdata;
  385. {
  386. #ifdef ZPIPE
  387.     char *compressfile, buf[BUFSIZ];
  388.     struct stat status;
  389.  
  390. #endif
  391.  
  392.     if (!filename) {
  393.     mdata->stream.file = (stdin);
  394.     mdata->type = XPMFILE;
  395.     } else {
  396. #ifdef ZPIPE
  397.     if (((int)strlen(filename) > 2) &&
  398.         !strcmp(".Z", filename + (strlen(filename) - 2))) {
  399.         mdata->type = XPMPIPE;
  400.         sprintf(buf, "uncompress -c %s", filename);
  401.         if (!(mdata->stream.file = popen(buf, "r")))
  402.         return (XpmOpenFailed);
  403.  
  404.     } else if (((int)strlen(filename) > 3) &&
  405.            !strcmp(".gz", filename + (strlen(filename) - 3))) {
  406.         mdata->type = XPMPIPE;
  407.         sprintf(buf, "gunzip -qc %s", filename);
  408.         if (!(mdata->stream.file = popen(buf, "r")))
  409.         return (XpmOpenFailed);
  410.  
  411.     } else {
  412.         if (!(compressfile = (char *) XpmMalloc(strlen(filename) + 4)))
  413.         return (XpmNoMemory);
  414.  
  415.         strcpy(compressfile, filename);
  416.         strcat(compressfile, ".Z");
  417.         if (!stat(compressfile, &status)) {
  418.         sprintf(buf, "uncompress -c %s", compressfile);
  419.         if (!(mdata->stream.file = popen(buf, "r"))) {
  420.             XpmFree(compressfile);
  421.             return (XpmOpenFailed);
  422.         }
  423.         mdata->type = XPMPIPE;
  424.         } else {
  425.         strcpy(compressfile, filename);
  426.         strcat(compressfile, ".gz");
  427.         if (!stat(compressfile, &status)) {
  428.             sprintf(buf, "gunzip -c %s", compressfile);
  429.             if (!(mdata->stream.file = popen(buf, "r"))) {
  430.             XpmFree(compressfile);
  431.             return (XpmOpenFailed);
  432.             }
  433.             mdata->type = XPMPIPE;
  434.         } else {
  435. #endif
  436.             if (!(mdata->stream.file = fopen(filename, "r"))) {
  437. #ifdef ZPIPE
  438.             XpmFree(compressfile);
  439. #endif
  440.             return (XpmOpenFailed);
  441.             }
  442.             mdata->type = XPMFILE;
  443. #ifdef ZPIPE
  444.         }
  445.         }
  446.         XpmFree(compressfile);
  447.     }
  448. #endif
  449.     }
  450.     mdata->CommentLength = 0;
  451.     return (XpmSuccess);
  452. }
  453.  
  454. /*
  455.  * open the given file to be written as an xpmData which is returned
  456.  */
  457. int
  458. xpmWriteFile(filename, mdata)
  459.     char *filename;
  460.     xpmData *mdata;
  461. {
  462. #ifdef ZPIPE
  463.     char buf[BUFSIZ];
  464.  
  465. #endif
  466.  
  467.     if (!filename) {
  468.     mdata->stream.file = (stdout);
  469.     mdata->type = XPMFILE;
  470.     } else {
  471. #ifdef ZPIPE
  472.     if ((int)strlen(filename) > 2
  473.         && !strcmp(".Z", filename + (strlen(filename) - 2))) {
  474.         sprintf(buf, "compress > %s", filename);
  475.         if (!(mdata->stream.file = popen(buf, "w")))
  476.         return (XpmOpenFailed);
  477.  
  478.         mdata->type = XPMPIPE;
  479.     } else if ((int)strlen(filename) > 3
  480.            && !strcmp(".gz", filename + (strlen(filename) - 3))) {
  481.         sprintf(buf, "gzip -q > %s", filename);
  482.         if (!(mdata->stream.file = popen(buf, "w")))
  483.         return (XpmOpenFailed);
  484.  
  485.         mdata->type = XPMPIPE;
  486.     } else {
  487. #endif
  488.         if (!(mdata->stream.file = fopen(filename, "w")))
  489.         return (XpmOpenFailed);
  490.  
  491.         mdata->type = XPMFILE;
  492. #ifdef ZPIPE
  493.     }
  494. #endif
  495.     }
  496.     return (XpmSuccess);
  497. }
  498.  
  499. /*
  500.  * open the given array to be read or written as an xpmData which is returned
  501.  */
  502. void
  503. xpmOpenArray(data, mdata)
  504.     char **data;
  505.     xpmData *mdata;
  506. {
  507.     mdata->type = XPMARRAY;
  508.     mdata->stream.data = data;
  509.     mdata->cptr = *data;
  510.     mdata->line = 0;
  511.     mdata->CommentLength = 0;
  512.     mdata->Bcmt = mdata->Ecmt = NULL;
  513.     mdata->Bos = mdata->Eos = '\0';
  514.     mdata->format = 0;        /* this can only be Xpm 2 or 3 */
  515. }
  516.  
  517. /*
  518.  * open the given buffer to be read or written as an xpmData which is returned
  519.  */
  520. void
  521. xpmOpenBuffer(buffer, mdata)
  522.     char *buffer;
  523.     xpmData *mdata;
  524. {
  525.     mdata->type = XPMBUFFER;
  526.     mdata->cptr = buffer;
  527.     mdata->CommentLength = 0;
  528. }
  529.  
  530. /*
  531.  * close the file related to the xpmData if any
  532.  */
  533. int
  534. xpmDataClose(mdata)
  535.     xpmData *mdata;
  536. {
  537.     switch (mdata->type) {
  538.     case XPMARRAY:
  539.     case XPMBUFFER:
  540.     break;
  541.     case XPMFILE:
  542.     if (mdata->stream.file != (stdout) && mdata->stream.file != (stdin))
  543.         fclose(mdata->stream.file);
  544.     break;
  545. #ifdef ZPIPE
  546.     case XPMPIPE:
  547.     pclose(mdata->stream.file);
  548.     break;
  549. #endif
  550.     }
  551.     return 0;
  552. }
  553.  
  554. xpmDataType xpmDataTypes[] =
  555. {
  556.     "", "!", "\n", '\0', '\n', "", "", "", "",    /* Natural type */
  557.     "C", "/*", "*/", '"', '"', ",\n", "static char *", "[] = {\n", "};\n",
  558.     "Lisp", ";", "\n", '"', '"', "\n", "(setq ", " '(\n", "))\n",
  559. #ifdef VMS
  560.     NULL
  561. #else
  562.     NULL, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL
  563. #endif
  564. };
  565.  
  566. /*
  567.  * parse xpm header
  568.  */
  569. int
  570. xpmParseHeader(mdata)
  571.     xpmData *mdata;
  572. {
  573.     char buf[BUFSIZ];
  574.     int l, n = 0;
  575.  
  576.     if (mdata->type) {
  577.     mdata->Bos = '\0';
  578.     mdata->Eos = '\n';
  579.     mdata->Bcmt = mdata->Ecmt = NULL;
  580.     l = xpmNextWord(mdata, buf, BUFSIZ);
  581.     if (l == 7 && !strncmp("#define", buf, 7)) {
  582.         /* this maybe an XPM 1 file */
  583.         char *ptr;
  584.  
  585.         l = xpmNextWord(mdata, buf, BUFSIZ);
  586.         if (!l)
  587.         return (XpmFileInvalid);
  588.         ptr = index(buf, '_');
  589.         if (!ptr || strncmp("_format", ptr, l - (ptr - buf)))
  590.         return XpmFileInvalid;
  591.         /* this is definitely an XPM 1 file */
  592.         mdata->format = 1;
  593.         n = 1;            /* handle XPM1 as mainly XPM2 C */
  594.     } else {
  595.  
  596.         /*
  597.          * skip the first word, get the second one, and see if this is
  598.          * XPM 2 or 3
  599.          */
  600.         l = xpmNextWord(mdata, buf, BUFSIZ);
  601.         if ((l == 3 && !strncmp("XPM", buf, 3)) ||
  602.         (l == 4 && !strncmp("XPM2", buf, 4))) {
  603.         if (l == 3)
  604.             n = 1;        /* handle XPM as XPM2 C */
  605.         else {
  606.             /* get the type key word */
  607.             l = xpmNextWord(mdata, buf, BUFSIZ);
  608.  
  609.             /*
  610.              * get infos about this type
  611.              */
  612.             while (xpmDataTypes[n].type
  613.                && strncmp(xpmDataTypes[n].type, buf, l))
  614.             n++;
  615.         }
  616.         mdata->format = 0;
  617.         } else
  618.         /* nope this is not an XPM file */
  619.         return XpmFileInvalid;
  620.     }
  621.     if (xpmDataTypes[n].type) {
  622.         if (n == 0) {        /* natural type */
  623.         mdata->Bcmt = xpmDataTypes[n].Bcmt;
  624.         mdata->Ecmt = xpmDataTypes[n].Ecmt;
  625.         xpmNextString(mdata);    /* skip the end of the headerline */
  626.         mdata->Bos = xpmDataTypes[n].Bos;
  627.         mdata->Eos = xpmDataTypes[n].Eos;
  628.         } else {
  629.         mdata->Bcmt = xpmDataTypes[n].Bcmt;
  630.         mdata->Ecmt = xpmDataTypes[n].Ecmt;
  631.         if (!mdata->format) {    /* XPM 2 or 3 */
  632.             mdata->Bos = xpmDataTypes[n].Bos;
  633.             mdata->Eos = '\0';
  634.             /* get to the beginning of the first string */
  635.             xpmNextString(mdata);
  636.             mdata->Eos = xpmDataTypes[n].Eos;
  637.         } else            /* XPM 1 skip end of line */
  638.             xpmNextString(mdata);
  639.         }
  640.     } else
  641.         /* we don't know about that type of XPM file... */
  642.         return XpmFileInvalid;
  643.     }
  644.     return XpmSuccess;
  645. }
  646.